/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package eu.easyedu.dictionary.editor;

import eu.easyedu.dictionary.api.model.Dictionary;
import eu.easyedu.dictionary.api.model.Language;
import eu.easyedu.dictionary.api.model.Word;
import eu.easyedu.dictionary.api.model.WordRelationship;
import eu.easyedu.dictionary.api.nservice.spi.AsynchronousSearch;
import eu.easyedu.dictionary.api.nservice.spi.WordBookService;
import eu.easyedu.dictionary.api.service.events.CreateEntityDictionaryEvent;
import eu.easyedu.dictionary.api.service.events.SearchEvent;
import eu.easyedu.dictionary.api.service.events.SearchEventListener;
import eu.easyedu.dictionary.api.service.events.SearchResultEvent;
import eu.easyedu.dictionary.api.service.events.WordBookEventListener;
import eu.easyedu.dictionary.api.util.ConnectionEvent;
import eu.easyedu.dictionary.api.util.ConnectionEventListener;
import eu.easyedu.dictionary.api.util.DictionaryManager;
import eu.easyedu.dictionary.api.options.DictionaryOptions;
import eu.easyedu.dictionary.api.util.DatabaseUtils;
import java.io.Serializable;
import java.util.List;
import java.util.ResourceBundle;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.openide.util.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

/**
 * Top component which displays something.
 */
final public class DefaultDictionaryWindowTopComponent extends TopComponent implements ConnectionEventListener,
        WordBookEventListener, SearchEventListener {

    private final static long serialVersionUID = 1L;
    private static final Logger log = Logger.getLogger(DefaultDictionaryWindowTopComponent.class.getName());
    private static DefaultDictionaryWindowTopComponent instance;
    private final static String DEFAULT_BUNDLE = "eu/easyedu/dictionary/editor/resources/Bundle";
    /** path to the icon used by the component and its open action */
    static final String ICON_PATH = "eu/easyedu/dictionary/gui/icons/dictionary16x16.png";
    private static final String PREFERRED_ID = "DefaultDictionaryWindowTopComponent";
    private static String[] RESULT_TABLE_COLUMN_NAMES = new String[]{
        java.util.ResourceBundle.getBundle(DEFAULT_BUNDLE).getString("DefaultDictionaryTopComponent.table.word"),
        java.util.ResourceBundle.getBundle(DEFAULT_BUNDLE).getString("DefaultDictionaryTopComponent.table.relationship"),
        java.util.ResourceBundle.getBundle(DEFAULT_BUNDLE).getString("DefaultDictionaryTopComponent.table.language")
    };
    private Dictionary dictionary;
    private WordBookService wbService;
    private AsynchronousSearch asyncSearch;

    private DefaultDictionaryWindowTopComponent() {
        initComponents();
        ResourceBundle bundle = NbBundle.getBundle("eu/easyedu/dictionary/editor/resources/Bundle");
        setName(bundle.getString("CTL_DefaultDictionaryWindowTopComponent"));
        setToolTipText(bundle.getString("HINT_DefaultDictionaryWindowTopComponent"));
        setIcon(ImageUtilities.loadImage(ICON_PATH, true));
        dictionary = DictionaryManager.getDefault().getDefaultDictionary();
        wbService = Lookup.getDefault().lookup(WordBookService.class);
        asyncSearch = new AsynchronousSearch(dictionary);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        searchTextField = new javax.swing.JTextField();
        searchLabel = new javax.swing.JLabel();
        resultSplitPane = new javax.swing.JSplitPane();
        wordListScrollPane = new javax.swing.JScrollPane();
        wordList = new javax.swing.JList();
        resultTableScrollPane = new javax.swing.JScrollPane();
        resultTable = new javax.swing.JTable();
        languageComboBox = new javax.swing.JComboBox();

        searchTextField.setBackground(new java.awt.Color(217, 217, 246));
        searchTextField.addCaretListener(new javax.swing.event.CaretListener() {
            public void caretUpdate(javax.swing.event.CaretEvent evt) {
                searchTextFieldCaretUpdate(evt);
            }
        });
        searchTextField.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                searchTextFieldActionPerformed(evt);
            }
        });

        searchLabel.setText(NbBundle.getBundle("eu/easyedu/dictionary/editor/resources/Bundle").getString( "DefaultDictionaryWindowTopComponent.searchLabel.text")); // NOI18N

        resultSplitPane.setDividerLocation(170);

        wordList.setModel(new DefaultListModel());
        wordList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                wordListValueChanged(evt);
            }
        });
        wordListScrollPane.setViewportView(wordList);

        resultSplitPane.setLeftComponent(wordListScrollPane);

        resultTable.setModel(getTranslationTableModel());
        resultTableScrollPane.setViewportView(resultTable);

        resultSplitPane.setRightComponent(resultTableScrollPane);

        languageComboBox.setEnabled(false);
        languageComboBox.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                languageComboBoxActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(resultSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 558, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addComponent(searchLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 98, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(searchTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(languageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 161, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(searchLabel)
                    .addComponent(languageComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(searchTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 29, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(resultSplitPane, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents
    private void searchTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchTextFieldActionPerformed
        asyncSearch.search(searchTextField.getText(), getSelectedLanguage());
    }//GEN-LAST:event_searchTextFieldActionPerformed

    private void searchTextFieldCaretUpdate(javax.swing.event.CaretEvent evt) {//GEN-FIRST:event_searchTextFieldCaretUpdate
        if (searchTextField.getText().length() >= Integer.MAX_VALUE) {
            asyncSearch.search(searchTextField.getText(), getSelectedLanguage());
        }
    }//GEN-LAST:event_searchTextFieldCaretUpdate

    private void languageComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_languageComboBoxActionPerformed
        asyncSearch.search(searchTextField.getText(), getSelectedLanguage());
    }//GEN-LAST:event_languageComboBoxActionPerformed

    private void wordListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_wordListValueChanged
        if (evt.getValueIsAdjusting() == false) {
            Word word = (Word) wordList.getSelectedValue();
            if (word != null) {
                List<WordRelationship> words = wbService.getAllRelatedWords(dictionary, word);
                setTranslationTableModel(words);
            }
        }
    }//GEN-LAST:event_wordListValueChanged

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JComboBox languageComboBox;
    private javax.swing.JSplitPane resultSplitPane;
    private javax.swing.JTable resultTable;
    private javax.swing.JScrollPane resultTableScrollPane;
    private javax.swing.JLabel searchLabel;
    private javax.swing.JTextField searchTextField;
    private javax.swing.JList wordList;
    private javax.swing.JScrollPane wordListScrollPane;
    // End of variables declaration//GEN-END:variables
    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link findInstance}.
     */
    public static synchronized DefaultDictionaryWindowTopComponent getDefault() {
        if (instance == null) {
            instance = new DefaultDictionaryWindowTopComponent();
        }
        return instance;
    }

    /**
     * Obtain the DefaultDictionaryWindowTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized DefaultDictionaryWindowTopComponent findInstance() {
        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
        if (win == null) {
            Logger.getLogger(DefaultDictionaryWindowTopComponent.class.getName()).warning(
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
            return getDefault();
        }
        if (win instanceof DefaultDictionaryWindowTopComponent) {
            return (DefaultDictionaryWindowTopComponent) win;
        }
        Logger.getLogger(DefaultDictionaryWindowTopComponent.class.getName()).warning(
                "There seem to be multiple components with the '" + PREFERRED_ID +
                "' ID. That is a potential source of errors and unexpected behavior.");
        return getDefault();
    }

    @Override
    public int getPersistenceType() {
        return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened() {
        System.out.println("SELECTED DICT: " + dictionary.getName());
        DatabaseUtils.addConnectionEventListener(dictionary, this);
        dictionary.addWordBookEventListener(this);
        asyncSearch.addSearchEventListener(this);
    }

    @Override
    public void componentClosed() {
        DatabaseUtils.removeConnectionEventListener(dictionary, this);
        dictionary.removeWordBookEventListener(this);
        asyncSearch.removeSearchEventListener(this);
    }

    /** replaces this in object stream */
    @Override
    public Object writeReplace() {
        return new ResolvableHelper();
    }

    @Override
    protected String preferredID() {
        return PREFERRED_ID;
    }

    final static class ResolvableHelper implements Serializable {

        private static final long serialVersionUID = 1L;

        public Object readResolve() {
            return DefaultDictionaryWindowTopComponent.getDefault();
        }
    }

    public TableModel getTranslationTableModel() {
        TableModel model = new DefaultTableModel(RESULT_TABLE_COLUMN_NAMES, 0) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        return model;
    }

    protected final void setTranslationTableModel(List<WordRelationship> words) {
        Object[][] data = new Object[words.size()][3];
        resultTable.getColumnModel().getColumn(1).setWidth(100);
        int idx = 0;
        for (WordRelationship rel : words) {
            data[idx][0] = rel.getRelatedWord().getWord();
            data[idx][1] = rel.getRelationship();
            data[idx][2] = rel.getRelatedWord().getLanguage();
            idx++;
        }
        DefaultTableModel model = (DefaultTableModel) resultTable.getModel();
        model.setDataVector(data, RESULT_TABLE_COLUMN_NAMES);
    }

    protected final void clearResultTable() {
        DefaultTableModel model = (DefaultTableModel) resultTable.getModel();
        model.setRowCount(0);
    }

    public void setSearchText(String searchText) {
        searchTextField.setText(searchText);
        searchTextField.postActionEvent();
    }

    public void connect(ConnectionEvent evt) {
        setConnected();
    }

    private void setConnected() {
        log.info("Setting icon to disconnect");
//        connectButton.setIcon(new javax.swing.ImageIcon(getClass().
//                getResource("/eu/easyedu/dictionary/gui/icons/disconnect.png")));
        languageComboBox.setEnabled(true);
//        refreshLanguageComboBox(dictionary.getLanguage());
        DictionaryOptions opts = DictionaryOptions.getInstance();
//        if (opts.isUnsetLanguage()) {
//            dictionary.setLanguage((Language) languageComboBox.getItemAt(0));
//        }
    }

    public void refreshLanguageComboBox(Language selectedItem) {
        DefaultComboBoxModel model = (DefaultComboBoxModel) languageComboBox.getModel();
        model.removeAllElements();
        for (Language language : wbService.getAllLanguages(dictionary)) {
            model.addElement(language);
        }
        if (selectedItem != null) {
            languageComboBox.setSelectedItem(selectedItem);
        }
    }

    public void disconnect(ConnectionEvent evt) {
        setDisconnected();
    }

    private void setDisconnected() {
        log.info("Setting icon to connect");
//        connectButton.setIcon(new javax.swing.ImageIcon(getClass().
//                getResource("/eu/easyedu/dictionary/gui/icons/connect.png")));
        languageComboBox.removeAllItems();
        languageComboBox.setEnabled(false);
    }

    public void searchStarted(SearchEvent evt) {
        log.info("Search started with word " + evt.getSearchString());
        clearResultTable();
        wordList.setListData(new Object[]{});
    }

    public void searchStopped(SearchResultEvent evt) {
        List<Word> searchResult = evt.getSearchResult();
        wordList.setListData(searchResult.toArray(searchResult.toArray()));
        if (searchResult.size() > 0) {
            wordList.setSelectedIndex(0);
        }
    }

    private Language getSelectedLanguage() {
        return (Language) languageComboBox.getSelectedItem();
    }

    public void addWord(CreateEntityDictionaryEvent<Word> evt) {
        // do nothing
        log.fine("New word " + evt.getSource() + " added.");
    }

    public void addLanguage(CreateEntityDictionaryEvent<Language> evt) {
        refreshLanguageComboBox(evt.getCreatedObject());
    }
}
